package rdb

import (
	"context"
	"encoding/json"
	"fmt"
	"sync"

	"github.com/redis/go-redis/v9"
)

type MapString interface {
	TopicKey() string
	RedisClient() *redis.Client
	Set(key string, value string) error
	Sets(kv map[string]string) error
	SetJson(key string, pointer any) error
	GetJson(key string, pointer any) error
	Get(key string) (string, error)
	Gets(keys []string) (map[string]string, error)
	GetAll() (map[string]string, error)
	Del(key string) error
	Dels(key []string) error
	Count() (int64, error)
	Scan(dest interface{}) error
	ClearAll() error
}

type _mapString struct {
	Topic string        //主题
	Redis *redis.Client //Redis客户端
	RWL   sync.RWMutex  //读写锁
}

func NewMapString(client *redis.Client, topic string) MapString {
	return &_mapString{
		Topic: topic,
		Redis: client,
		RWL:   sync.RWMutex{},
	}
}

// TopicKey 返回默认生成的主题key
func (m *_mapString) TopicKey() string {
	return fmt.Sprint("MapString_", m.Topic)
}

// RedisClient 返回绑定的Redis客户端
func (m *_mapString) RedisClient() *redis.Client {
	return m.Redis
}

func (m *_mapString) Set(key string, value string) error {
	m.RWL.Lock()
	err := m.Redis.HSet(context.Background(), m.TopicKey(), key, value).Err()
	m.RWL.Unlock()
	return err
}

func (m *_mapString) Sets(kv map[string]string) error {
	m.RWL.Lock()
	var temp = make([]any, 0, len(kv)*2)
	for k, v := range kv {
		temp = append(temp, k)
		temp = append(temp, v)
	}
	err := m.Redis.HMSet(context.Background(), m.TopicKey(), temp...).Err()
	m.RWL.Unlock()
	return err
}

func (m *_mapString) SetJson(key string, pointer any) error {
	marshal, err := json.Marshal(pointer)
	if err != nil {
		return err
	}
	m.RWL.Lock()
	err = m.Redis.HSet(context.Background(), m.TopicKey(), key, string(marshal)).Err()
	m.RWL.Unlock()
	return err
}

func (m *_mapString) GetJson(key string, pointer any) error {
	m.RWL.RLock()
	result, err := m.Redis.HGet(context.Background(), m.TopicKey(), key).Result()
	m.RWL.RUnlock()
	if err != nil {
		return err
	}
	err = json.Unmarshal([]byte(result), pointer)
	return err
}

func (m *_mapString) Get(key string) (string, error) {
	m.RWL.RLock()
	result, err := m.Redis.HGet(context.Background(), m.TopicKey(), key).Result()
	m.RWL.RUnlock()
	return result, err
}

func (m *_mapString) Gets(keys []string) (map[string]string, error) {
	m.RWL.RLock()
	result, err := m.Redis.HMGet(context.Background(), m.TopicKey(), keys...).Result()
	m.RWL.RUnlock()
	var temp = make(map[string]string)
	for i := 0; i < len(keys); i++ {
		if result[i] != nil {
			temp[keys[i]] = fmt.Sprint(result[i])
		}
	}
	return temp, err
}

func (m *_mapString) GetAll() (map[string]string, error) {
	m.RWL.RLock()
	result, err := m.Redis.HGetAll(context.Background(), m.TopicKey()).Result()
	m.RWL.RUnlock()
	return result, err
}

func (m *_mapString) Del(key string) error {
	m.RWL.Lock()
	err := m.Redis.HDel(context.Background(), m.TopicKey(), key).Err()
	m.RWL.Unlock()
	return err
}

func (m *_mapString) Dels(key []string) error {
	m.RWL.Lock()
	err := m.Redis.HDel(context.Background(), m.TopicKey(), key...).Err()
	m.RWL.Unlock()
	return err
}

// Count 获取哈希表中字段的数量
func (m *_mapString) Count() (int64, error) {
	m.RWL.RLock()
	defer m.RWL.RUnlock()
	result, err := m.Redis.HLen(context.Background(), m.TopicKey()).Result()
	if err == nil || err == redis.Nil {
		return result, nil
	}
	return result, err
}

// Scan 将结果扫描到目标结构体中
func (m *_mapString) Scan(dest interface{}) error {
	m.RWL.RLock()
	err := m.Redis.HGetAll(context.Background(), m.TopicKey()).Scan(dest)
	m.RWL.RUnlock()
	return err
}

// ClearAll 清空所有的记录（直接删除key）
func (m *_mapString) ClearAll() error {
	m.RWL.Lock()
	err := m.Redis.Del(context.Background(), m.TopicKey()).Err()
	m.RWL.Unlock()
	return err
}
